#include "AnalysisKLV.h"
#include <cmath>
using std::pair;
#include <string.h>

AnalysisKLV::AnalysisKLV(/* args */)
{
    m_KlvType.insert(std::pair<int,tagKLV>(0x0001,tagKLV("NCHAR","终端软件程序版本          ")));
    m_KlvType.insert(std::pair<int,tagKLV>(0x0002,tagKLV("NCHAR","终端菜单版本              ")));
    m_KlvType.insert(std::pair<int,tagKLV>(0x0008,tagKLV("NCHAR","存储网关号码,终端升级使用的")));
    m_KlvType.insert(std::pair<int,tagKLV>(0x0009,tagKLV("HEX"  ,"终端类型                         ")));
    m_KlvType.insert(std::pair<int,tagKLV>(0x000A,tagKLV("NUM",  "终端子设备数目                   ")));
    m_KlvType.insert(std::pair<int,tagKLV>(0x000B,tagKLV("HEX",  "网管用户标识1                    ")));
    m_KlvType.insert(std::pair<int,tagKLV>(0x000C,tagKLV("NUM",  "升级策略                         ")));
    m_KlvType.insert(std::pair<int,tagKLV>(0x000D,tagKLV("NUM",  "升级开始时间                     ")));
    
    
    m_KlvType.insert(std::pair<int,tagKLV>(0x0026,tagKLV("NUM",  "存储网关子设备号码               ")));
    m_KlvType.insert(std::pair<int,tagKLV>(0x002D,tagKLV("HEX",  "会管用户标识                     ")));
    m_KlvType.insert(std::pair<int,tagKLV>(0x002E,tagKLV("NCHAR","内核版本                    ")));
    m_KlvType.insert(std::pair<int,tagKLV>(0x002F,tagKLV("NCHAR","文件系统版本                ")));
    
    m_KlvType.insert(std::pair<int,tagKLV>(0x0030,tagKLV("NCHAR","存储网关号码                ")));
    m_KlvType.insert(std::pair<int,tagKLV>(0x0046,tagKLV("NCHAR","桥接服务器号码               ")));
    
    m_KlvType.insert(std::pair<int,tagKLV>(0x006C,tagKLV("NCHAR","字库版本                    ")));
    
    m_KlvType.insert(std::pair<int,tagKLV>(0x0071,tagKLV("HEX","会管用户标识2                    ")));
    m_KlvType.insert(std::pair<int,tagKLV>(0x0072,tagKLV("HEX","终端配置开关                     ")));
    m_KlvType.insert(std::pair<int,tagKLV>(0x0084,tagKLV("HEX","管控平台号码                      ")));
    m_KlvType.insert(std::pair<int,tagKLV>(0x0099,tagKLV("NUM","密级                             ")));
    m_KlvType.insert(std::pair<int,tagKLV>(0x00A8,tagKLV("NCHAR","行政区域                         ")));
    
    
    m_funtype["NCHAR"] = &AnalysisKLV::funNCHAR;
    m_funtype["HEX"]   = &AnalysisKLV::funHEX;
    m_funtype["NUM"]   = &AnalysisKLV::funNUM;
}

AnalysisKLV::~AnalysisKLV()
{

}

std::string AnalysisKLV::ToHexString(const unsigned char* pData,size_t nSize)
{
    std::string str;
    char szBuf[1024] = "";
    for(size_t i = 0;i<nSize;i++)
    {
        std::snprintf(szBuf,1024,"%02X",*(pData+i));
        str +=szBuf;
    }
    return str;
}


std::string AnalysisKLV::funNCHAR(const unsigned char * uBuf, const int iLen)
{
    std::string retStr = (const char*)uBuf;
    return retStr;
}

std::string AnalysisKLV::funHEX(const unsigned char * uBuf, const int iLen)
{  
    std::string retStr = "0x";
    retStr += ToHexString(uBuf,iLen);
    return retStr;
}

std::string AnalysisKLV::funNUM(const unsigned char * uBuf, const int iLen)
{  
    std::string retStr = "";
    int val = 0;
    int digit = iLen;
    
    for(int i = 0 ; i < iLen ; i++)
    {
        int tempval = uBuf[i] * pow(256,digit -1);
        val += tempval;
        digit--;
    }
    retStr = std::to_string(val);
    return retStr;
}



void AnalysisKLV::TrimStr(const char *oriStr, char *resStr)
{
    const char *p = oriStr;
    while (*p)
    {
        if (*p != ' ')
        {
            *resStr++ = *p;
        }
        ++p;
    }
    *resStr = '\0';
}

int AnalysisKLV::ascii2hex(char ch)
{
    if ((ch <= 0x39) && (ch >= 0x30))           // 0 ~ 9
        return (ch- 0x30);
    else if ((ch <= 0x66) && (ch >= 0x61))      // a ~ f
        return  (ch - 0x61 + 10);
    else if ((ch <= 0x46) && (ch >= 0x41))	    // A ~ F
        return (ch - 0x41 + 10);
    return 0;
}

int AnalysisKLV::str2hex(char* szStr, int szlen, char* szHex, int hexlen)
{
    if (szlen % 2) return -1;
    unsigned high, low;
    int len = szlen / 2;
    for (int i=0;i< len;i++)
    {
        if(i >= hexlen)
            return i;
        high = ascii2hex(szStr[2*i]);
        low  = ascii2hex(szStr[2*i+1]);
        szHex[i] = (high << 4) | low;
    }
    return 0;
}


int AnalysisKLV::Analysis(char* pInputBuf)
{
    int srcLen = strlen(pInputBuf);
    
    unsigned char *pdst = (unsigned char*)malloc(srcLen + 1);
    unsigned char *pHexBuf = (unsigned char*)malloc(srcLen + 1);
    TrimStr(pInputBuf,(char*)pdst);
    int dstLen = strlen((char*)pdst);
    
    if(0 != str2hex((char*)pdst,dstLen,(char*)pHexBuf,dstLen / 2))
    {
        printf("Please enter the correct message\n");
        free(pdst);
        free(pHexBuf);
        return -1;
    }
    dstLen /= 2;
    int iPos = 0;
    while(dstLen >= 4)
    {
        int k = pHexBuf[iPos] * 256 + pHexBuf[iPos + 1];
        std::map<int,tagKLV>::iterator klvit =m_KlvType.find(k);
        if(klvit != m_KlvType.end())
        {
            int l = pHexBuf[iPos + 2] * 256 + pHexBuf[iPos + 3];
            if(0 == l)
            {
                iPos += 4;
                dstLen -= 4;
                continue;
            }
            if( 2 + 2 + l > dstLen)
            {
                printf("\ndata is not enough len\n");
                break;
            }
            std::map<std::string,std::string (*)(const unsigned char *, const int)>::iterator funiter = m_funtype.find(klvit->second.fun);
            if(funiter != m_funtype.end())
            {
                char* data = (char*)malloc(l + 1);
                memcpy(data,pHexBuf+ iPos + 4,l);
                printf("k:%04X = %s ,l = %04X ",klvit->first,klvit->second.msg.c_str(),l);
                printf(", v = %s\n",funiter->second((const unsigned char*)data,l).c_str());
    
                funiter->second((const unsigned char*)data,l);
                free(data);
            }
            else
            {
                printf("\nthe parsing method is undefined !\n");
            }
            iPos = iPos + 2 + 2 + l;
            dstLen -= (2 + 2 + l);
            // printf("iPos = %d,dstLen = %d\n",iPos,dstLen);
        }
        else
        {
    
            //printf("\n%04X \n",k);
            printf("\nskip this byte ,the pos is %d !\n",iPos);
            iPos++;
            dstLen--;
        }
    }
    free(pdst);
    free(pHexBuf);
    return 0;
}

